﻿#if IAP
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Purchasing;
using UnityEngine.ChannelPurchase;
using UnityEngine.Purchasing.Security;
using UnityEngine.Store;
using System;
using System.IO;
using Newtonsoft.Json;

public class IAPParam
{
    public string goodsId;//游戏内商品ID
    public string productPid;//不同支付平台不同商品ID

    public string payload
    {
        get { return $"{goodsId}_{productPid}"; }
    }

    public IAPParam(string goodsId, string productPid)
    {
        this.goodsId = goodsId;
        this.productPid = productPid;
    }
}

public class PaymentData
{
    public string goodsId;//游戏内商品ID
    public string productPid;//不同支付平台不同商品ID
    public int payType;
    public string transaction;
    public string receipt;
}

public class IAPProduct
{
    public bool enabled;
    public string id;//商品id
    public string storeSpecificId;

    public string localizedTitle;
    public string localizeDescription;
    public decimal localizedPrice;
    public string localizedPriceString;

    public IAPProduct()
    {
    }

    public IAPProduct(UnityEngine.Purchasing.Product p)
    {
        this.enabled = p.definition.enabled;
        this.id = p.definition.id;
        this.storeSpecificId = p.definition.storeSpecificId;

        this.localizedTitle = p.metadata.localizedTitle;
        this.localizeDescription = p.metadata.localizedDescription;
        this.localizedPrice = p.metadata.localizedPrice;
        this.localizedPriceString = p.metadata.localizedPriceString;
    }

    public void Log()
    {
        GameDebug.Log($"enabled:{enabled},id:{id},storeSpecificId:{storeSpecificId},localizedTitle:{localizedTitle},localizeDescription:{localizeDescription},localizedPrice:{localizedPrice},localizedPriceString:{localizedPriceString}");
    }
}

public class IAPProductCollection
{
    IAPProduct[] m_Products;
    public IAPProduct[] products
    {
        get
        {
            return m_Products;
        }
    }

    public bool hasData
    {
        get
        {
            return (m_Products == null || m_Products.Length == 0) ? false : true;
        }
    }

    string persistentDataPath;

    string savePath
    {
        get
        {
            string folder = persistentDataPath + "/iap";
            if (!System.IO.Directory.Exists(folder))
            {
                System.IO.Directory.CreateDirectory(folder);
#if UNITY_IOS || UNITY_IPHONE
                GameDebug.Log("设置文件夹不备份,folder:" + folder);
                UnityEngine.iOS.Device.SetNoBackupFlag(folder);
#endif
            }
            return folder + "/products.data";
        }
    }

    public IAPProductCollection()
    {
        persistentDataPath = UnityEngine.Application.persistentDataPath;
        ReadFromFile();
    }

    public void Init(UnityEngine.Purchasing.Product[] products)
    {
        if (products == null || products.Length == 0)
        {
            GameDebug.LogError("products is null");
            return;
        }

        int count = products.Length;
        this.m_Products = new IAPProduct[count];
        for (int i = 0; i < count; ++i)
        {
            this.m_Products[i] = new IAPProduct(products[i]);
        }

        Save2File();
    }

    public IAPProduct WithID(string id)
    {
        if (string.IsNullOrEmpty(id))
        {
            GameDebug.LogError("product with id,id is null");
            return null;
        }
        if (this.m_Products == null)
        {
            GameDebug.LogError("product with id,products is null");
            return null;
        }

        IAPProduct product = Array.Find<IAPProduct>(this.m_Products, p => p.id.Equals(id));

        if (product == null)
            GameDebug.LogError("product with id,product is null,id:" + id);

        return product;
    }

    /// <summary>
    /// 获取本地价格字符串
    /// </summary>
    /// <param name="productIp"></param>
    /// <returns></returns>
    public string GetLocalPriceString(string productIp)
    {
        IAPProduct iapProduct = WithID(productIp);
        if (iapProduct != null)
        {
            return iapProduct.localizedPriceString;
        }

        return "";
    }

    public void ReadFromFile()
    {
        try
        {
            string path = this.savePath;
            if (!File.Exists(path))
                return;

            string json = File.ReadAllText(path);
            if (string.IsNullOrEmpty(json))
                return;

            this.m_Products = JsonConvert.DeserializeObject<IAPProduct[]>(json);
        }
        catch (Exception e)
        {
            GameDebug.LogError($"从本地加载商品数据出错,路径{savePath},错误:{e}");
        }
    }

    public void Save2File()
    {
        try
        {
            if (m_Products == null || m_Products.Length == 0)
                return;

            string json = JsonConvert.SerializeObject(m_Products);
            File.WriteAllText(savePath, json);
        }
        catch (Exception e)
        {
            GameDebug.LogError($"写商品数据到本地,路径{savePath},错误:{e}");
        }
    }
}

public class UnityIAPController : MonoBehaviour, IStoreListener
{
    IStoreController m_Ctrl;
    IExtensionProvider m_Extensions;

    /// <summary>
    /// 商品集合
    /// </summary>
    IAPProductCollection m_Products;
    public IAPProductCollection products
    {
        get
        {
            return m_Products;
        }
    }

    public bool hasInited
    {
        get
        {
            return m_Ctrl != null && m_Extensions != null;
        }
    }

    const string s_Key_ShouldCheckRestore = "Key_ShouldCheckRestore";
    /// <summary>
    /// 是否要唤起支付恢复，此值用于在同一个appstore账号,不同的游戏帐号之间共享购买过的非消耗型的商品
    /// </summary>
    public static bool shouldCheckRestore
    {
        get
        {
            return PlayerPrefs.GetInt(s_Key_ShouldCheckRestore, 0) > 0;
        }
        set
        {
            PlayerPrefs.SetInt(s_Key_ShouldCheckRestore, value ? 1 : 0);
        }
    }

    /// <summary>
    /// 支付失败回调
    /// </summary>
    Action<string> m_PayFail;
    /// <summary>
    /// 支付成功回调
    /// </summary>
    Action<PaymentData> m_PaySuccess;
    /// <summary>
    /// 支付恢复中，若在支付恢复中收到支付失败回调也不弹窗提示
    /// </summary>
    bool m_InRestoreing = false;

    /// <summary>
    /// 是否漏单处理中
    /// </summary>
    bool isDropOrderProcessing = false;

    /// <summary>
    /// 是否是谷歌支付
    /// </summary>
    // bool m_IsGooglePay;
    private PayType m_PayType;

    const string Key_CurGoodsID = "Key_CurGoodsID";
    const string Key_CurReceipt = "Key_CurReceipt";
    const string Key_CurTransactionID = "Key_CurTransactionID";
    const string Key_CurProductId = "Key_CurProductId";
    /*const string Key_LastPaymentId = "Key_LastPaymentId";
    const string Key_LastPaymentOrder = "Key_LastPaymentOrder";*/

    /// <summary>
    /// 上一次支付的游戏商品id，用于漏单处理
    /// </summary>
    public static string curGoodsID
    {
        get
        {
            return PlayerPrefs.GetString(Key_CurGoodsID);
        }
        set
        {
            PlayerPrefs.SetString(Key_CurGoodsID, value);
        }
    }
    public static string curReceipt
    {
        get
        {
            return PlayerPrefs.GetString(Key_CurReceipt);
        }
        set
        {
            PlayerPrefs.SetString(Key_CurReceipt, value);
        }
    }
    public static string curTransactionID
    {
        get
        {
            return PlayerPrefs.GetString(Key_CurTransactionID);
        }
        set
        {
            PlayerPrefs.SetString(Key_CurTransactionID, value);
        }
    }
    public static string curProductId
    {
        get
        {
            return PlayerPrefs.GetString(Key_CurProductId);
        }
        set
        {
            PlayerPrefs.SetString(Key_CurProductId, value);
        }
    }
    /*public static string lastPaymentId
    {
        get
        {
            return PlayerPrefs.GetString(Key_LastPaymentId);
        }
        set
        {
            PlayerPrefs.SetString(Key_LastPaymentId, value);
        }
    }
    public static string lastPaymentOrder
    {
        get
        {
            return PlayerPrefs.GetString(Key_LastPaymentOrder);
        }
        set
        {
            PlayerPrefs.SetString(Key_LastPaymentOrder, value);
        }
    }*/

    IAPParam m_IapParam;

    /// <summary>
    /// 当前正在支付的product
    /// </summary>
    Product m_CurProduct;

    //是否开启了log模式
    bool isShowLog
    {
        get
        {
            if (GameCtrl.Instance.config != null)
                return GameCtrl.Instance.config.ShowIAPLog;
            else
                return false;
        }
    }

    private void Start()
    {
        
    }

    private Action m_OnInitEnd;
    public void Init(PayType payType,Action onEnd)
    { 
        m_PayType = payType;
        m_OnInitEnd = onEnd;
        
        this.m_Products = new IAPProductCollection();
        #if UNITY_IOS
        StandardPurchasingModule module = StandardPurchasingModule.Instance(AppStore.AppleAppStore);
        #else
        StandardPurchasingModule module = StandardPurchasingModule.Instance();
        #endif
        var builder = ConfigurationBuilder.Instance(module);
        
        GoodsArche[] productArches = ConstData.Instance.goods.AllWhere(e => e.useMoney).AsArray();
        
        GameDebug.LogShowy($"当前支付类型：{m_PayType.ToString()}  productArches:{productArches.GetArrStr()}");
        foreach (var goodsArche in productArches)
        {
            builder.AddProduct(UnityPayCtrl.GetProductID(goodsArche,m_PayType), ProductType.Consumable);
        }

        UnityPurchasing.Initialize(this, builder);
        GameDebug.LogShowy("=============init IAPManager==============");
    }

    public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
    {
        this.m_Ctrl = controller;
        this.m_Extensions = extensions;

        LogProduct();

        this.m_Products.Init(controller.products.all);

        m_OnInitEnd?.Invoke();
        GameDebug.LogShowy("<color=yellow>IAPManager.OnInitialized completed</color>");
    }

    void LogProduct()
    {
        GameDebug.LogShowy("OnInitialized log product---------------------------------------");
        Product item = null;
        for (int i = 0; i < m_Ctrl.products.all.Length; ++i)
        {
            item = m_Ctrl.products.all[i];
            GameDebug.LogShowy($"第{(i + 1)}个商品--[[productId:{item.definition.id}],localizedTitle:{item.metadata.localizedTitle}],[localizedPriceString:{item.metadata.localizedPriceString}]");
        }
        GameDebug.LogShowy("OnInitialized log product---------------------------------------");
    }

    /// <summary>
    /// 支付
    /// </summary>
    public void Purchase(
        IAPParam iapParam, Action<string> onPayFail,
        Action<PaymentData> onPaySuccess)
    {
        //漏单处理中,提示玩家等待处理结束后购买
        if (isDropOrderProcessing)
        {
            // Localization.instance.GetValue("order_processing_wait");//漏单处理中，请等待漏单处理结束后再进行购买
            ShowNotice(Localization.instance.GetValue("order_processing_wait"));
            return;
        }

        this.m_IapParam = iapParam;
        this.m_PayFail = onPayFail;
        this.m_PaySuccess = onPaySuccess;

        string productId = iapParam.productPid;

        GameDebug.LogShowy($"Purchase productId:{productId} ,payType:{GetPayType()}");

        if (m_PayType == PayType.EDITOR)
        {
            m_PaySuccess?.Invoke(new PaymentData()
            {
                goodsId =  iapParam.goodsId,
                productPid =  productId,
                payType =  (int)m_PayType,
                transaction =  "editor transaction",
                receipt = "test"
            });
            return;
        }

        if (m_Ctrl != null)//已初始化
        {
            m_CurProduct = m_Ctrl.products.WithID(productId);
            if (m_CurProduct != null)
            {
                if (m_CurProduct.availableToPurchase)
                {
                    //记录支付信息
                    RecordPayInfo();

                    //向iap发起支付
                    GameDebug.LogShowy("Purchase,paymentOrder:" + iapParam.goodsId);
                    m_Ctrl.InitiatePurchase(m_CurProduct, iapParam.payload);
                    GameDebug.LogShowy($"Purchase,m_Ctrl.InitiatePurchase,productId:{productId}");
                }
                else
                {
                    HideMaskAndConfirmPurchase();
                    if (onPayFail != null)
                        onPayFail($"<color=red>no available product:{productId}</color>");
                }
            }
            else
            {
                HideMaskAndConfirmPurchase();
                if (onPayFail != null)
                    onPayFail($"<color=red>can no find product:{productId}</color>");
            }
        }
        else//iap未初始化，进行初始化确认
        {
            HideMaskAndConfirmPurchase();

            PayType payType = m_PayType;

            if (payType == PayType.None)
            {
                GameDebug.LogError($"m_PayType == PayType.None");
                payType = GetPayType();
            }
                     
            Init(payType,null);
            
            onPayFail?.Invoke(Localization.instance.GetValue("iap_init_tips"));
        }
    }

    /// <summary>
    /// 支付成功的回调
    /// </summary>
    /// <param name="e"></param>
    /// <returns></returns>
    public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs e)
    {
        try
        {
            //有非消耗型商品时可用m_InRestoreing判断是否是恢复购买的回调
            GameDebug.Log("PurchaseProcessingResult");

            m_CurProduct = e.purchasedProduct;

            //恢复支付或漏单处理时m_IapParam为空
            if (m_IapParam == null)
            {
                GameDebug.Log("ProcessPurchase  m_IapParam is null");

                if (!CheckIapParamNull())
                {
                    GameDebug.LogError("CheckIapParamNull return false，PurchaseProcessingResult.Complete");
                    HideMaskAndConfirmPurchase();
                    return PurchaseProcessingResult.Complete;
                }
            }

            UnifiedReceipt receiptObj = JsonUtility.FromJson<UnifiedReceipt>(e.purchasedProduct.receipt);

            GameDebug.Log($"compare productID:{curProductId.Equals(e.purchasedProduct.definition.id)}");

            if (receiptObj != null && !string.IsNullOrEmpty(receiptObj.Payload) && curProductId.Equals(e.purchasedProduct.definition.id))
            {
                GameDebug.LogShowy($"ProcessPurchase Id:{ e.purchasedProduct.definition.id}");
                GameDebug.LogShowy($"[ProcessPurchase transactionID:{e.purchasedProduct.transactionID}]");
                GameDebug.LogShowy($"ProcessPurchase receipt:{e.purchasedProduct.receipt}");

                string receiptStr = (string)receiptObj.Payload;

                //支付成功 验证前 记录凭证等数据
                curProductId = e.purchasedProduct.definition.id;
                curReceipt = receiptStr;
                curTransactionID = e.purchasedProduct.transactionID;
                
                OnPurchaseSuccess(curGoodsID, curProductId, e.purchasedProduct.transactionID, receiptStr);// 服务器验证
                
                ClientLog.Send(ClientLogId.PaySuc,$"ProductId:{e.purchasedProduct.definition.id}  curGoodsID:{curGoodsID}");
            }
            else
            {
                if (receiptObj == null)
                {
                    this.m_PayFail?.Invoke($"receiptObj null");
                }
                else if (string.IsNullOrEmpty(receiptObj.Payload))
                {
                    this.m_PayFail?.Invoke($"receiptObj.Payload null");
                }
                else
                {
                    this.m_PayFail?.Invoke($"curProductId:{curProductId}  not equal :{e.purchasedProduct.definition.id}");
                }
            }
            
            return PurchaseProcessingResult.Complete;
        }
        catch (Exception e1)
        {
            string message = "ProcessPurchase,error:\n" + e1;
            GameDebug.LogError(message);
            ShowNotice("ProcessPurchase error");
            return PurchaseProcessingResult.Complete;
        }
    }

    /// <summary>
    /// 记录本次支付信息
    /// </summary>
    void RecordPayInfo()
    {
        AddNotValidPayInfo();

        ClearLastRecord();

        curGoodsID = m_IapParam.goodsId;
        curProductId = m_IapParam.productPid;
        GameDebug.LogShowy("RecordPayInfo");
    }

    #region 漏单处理

    const string KEY_NotValidPayInfo = "KEY_NotValidPayInfo";

    /// <summary>
    /// 在记录当前支付信息时，记录下未验证成功的信息
    /// 目的：防止出现 第一次支付验证失败，第二次支付验证成功时，第二次的支付信息覆盖掉第一次的支付信息
    /// </summary>
    void AddNotValidPayInfo()
    {
        if (
            !string.IsNullOrEmpty(curGoodsID) &&
            !string.IsNullOrEmpty(curProductId) &&
            !string.IsNullOrEmpty(curTransactionID) &&
            !string.IsNullOrEmpty(curReceipt)
        )
        {
            ValidPayInfo validPayInfo = new ValidPayInfo(curGoodsID, curProductId,  curTransactionID, curReceipt);

            List<ValidPayInfo> infoList = new List<ValidPayInfo>();

            ValidPayInfo[] infos = ParseNotValidPayInfo();

            if (infos != null)
                infoList.AddRange(infos);

            infoList.Add(validPayInfo);

            SaveNotValidPayInfo(infoList);
        }
    }

    void SaveNotValidPayInfo(List<ValidPayInfo> infos)
    {
        if (infos == null)
        {
            PlayerPrefs.SetString(KEY_NotValidPayInfo, "");
            return;
        }

        string json = JsonConvert.SerializeObject(infos.ToArray());
        PlayerPrefs.SetString(KEY_NotValidPayInfo, json);
        GameDebug.LogShowy("因为上一次验证失败了同时又一次购买 记录上一次的支付信息");
    }

    class ValidPayInfo
    {
        string m_GoodsID;
        string m_InternalPid;
        string m_TransactionID;
        string m_Receipt;

        public string goodsId
        {
            get
            {
                return m_GoodsID;
            }
        }
        public string internalPid
        {
            get
            {
                return m_InternalPid;
            }
        }
        public string transactionId
        {
            get
            {
                return m_TransactionID;
            }
        }
        public string receipt
        {
            get
            {
                return m_Receipt;
            }
        }

        public ValidPayInfo(string goodsId, string internalPid,  string transactionId, string receipt)
        {
            m_GoodsID = goodsId;
            m_InternalPid = internalPid;
            m_TransactionID = transactionId;
            m_Receipt = receipt;
        }

        public bool IsEqual(string goodsId, string internalPid)
        {
            return
                 m_InternalPid.Equals(internalPid) &&
                 goodsId.Equals(goodsId);
        }

        public void Log()
        {
            GameDebug.LogError($"m_LastProductID:{m_GoodsID},m_LastInternalPid:{m_InternalPid},m_LastTransactionID:{m_TransactionID},m_LastReceipt:{m_Receipt}");
        }
    }

    ValidPayInfo[] ParseNotValidPayInfo()
    {
        try
        {
            string json = PlayerPrefs.GetString(KEY_NotValidPayInfo, "");
            if (string.IsNullOrEmpty(json))
            {
                return null;
            }
            else
            {
                return JsonConvert.DeserializeObject<ValidPayInfo[]>(json);
            }
        }
        catch (Exception e)
        {
            GameDebug.LogError(e);
            return null;
        }
    }

    //AtomLock atomLock = new AtomLock();

    /// <summary>
    /// 更新ValidPayInfo
    /// </summary>
    void UpdateValidPayInfo(string goodsId,string productPid)
    {
        //atomLock.DoAction(delegate
        {
            ValidPayInfo[] infos = ParseNotValidPayInfo();

            if (infos != null && infos.Length > 0)
            {
                List<ValidPayInfo> infoList = new List<ValidPayInfo>();
                infoList.AddRange(infos);

                ValidPayInfo curInfo = null;

                for (int i = 0; i < infoList.Count; ++i)
                {
                    if (infoList[i].IsEqual(goodsId,productPid))
                    {
                        curInfo = infoList[i];
                        break;
                    }
                }

                if (curInfo != null)
                {
                    infoList.Remove(curInfo);
                    SaveNotValidPayInfo(infoList);
                    GameDebug.LogShowy("更新ValidPayInfo");
                }
            }else
            {
                PlayerPrefs.SetString(KEY_NotValidPayInfo, "");
            }
        }
        //);
    }

    /// <summary>
    /// 检测是否有订单没有发到服务器，进行漏单处理
    /// </summary>
    public void CheckDropOrder()
    {
        try
        {
            GameDebug.LogShowy("CheckDropOrder");
            StartCoroutine(DelayCheckDropOrder());

        }
        catch (Exception e)
        {
            GameDebug.LogError("Exception:CheckDropOrder,error:\n" + e);
            string message = isShowLog ? Localization.instance.GetValue("pay_verify_fail") + "_4" : Localization.instance.GetValue("pay_verify_fail");
            ShowNotice(message);
        }
    }

    IEnumerator DelayCheckDropOrder()
    {
        while (m_Ctrl == null)
            yield return null;

        LogLastPayInfo();

        //检测漏单
        if (
            !string.IsNullOrEmpty(curGoodsID) &&
            !string.IsNullOrEmpty(curReceipt) &&
            !string.IsNullOrEmpty(curTransactionID) &&
            !string.IsNullOrEmpty(curProductId)
            )
            
        {
            DropOrderProcessing(curGoodsID, curProductId,curTransactionID, curReceipt);
        }

        //检测未验证的单据
        ValidPayInfo[] infos = ParseNotValidPayInfo();
        if (infos != null && infos.Length > 0)
        {
            for (int i = 0; i < infos.Length; ++i)
            {
                yield return new WaitForSeconds(0.1f);
                DropOrderProcessing(infos[i].goodsId, infos[i].internalPid,infos[i].transactionId, infos[i].receipt);
            }
        }
    }

    #endregion

    /// <summary>
    /// 恢复购买
    /// </summary>
    public void CheckRestore()
    {
        shouldCheckRestore = true;
        RestroePurchase();
    }

    /// <summary>
    /// 恢复支付
    /// </summary>
    void RestroePurchase()
    {
        if (!hasInited)
        {
            GameDebug.LogError("<color=red>ips hasInited == false</color>");
            return;
        }

        GameDebug.Log("<color=yellow>RestroePurchase============================</color>");

        m_InRestoreing = true;
        shouldCheckRestore = false;

        if (Application.isEditor)
        {
#if UNITY_EDITOR
            if (editorPayType == PayType.IOS)
            {
                IAppleExtensions appleExtensions = m_Extensions.GetExtension<IAppleExtensions>();
                appleExtensions.RestoreTransactions(RestroedHandle);
            }
            else if (editorPayType == PayType.Google)
            {
                IGooglePlayStoreExtensions googleExtensions = m_Extensions.GetExtension<IGooglePlayStoreExtensions>();
                googleExtensions.RestoreTransactions(RestroedHandle);
            }
            else if (editorPayType == PayType.UDP)
            {
                IUDPExtensions googleExtensions = m_Extensions.GetExtension<IUDPExtensions>();
                
                GameDebug.Log("RestroePurchase fail , udpExtensions not support");
            }
#endif
        }
        else if (
            Application.platform == RuntimePlatform.IPhonePlayer ||
            Application.platform == RuntimePlatform.OSXPlayer
            )
        {
            IAppleExtensions appleExtensions = m_Extensions.GetExtension<IAppleExtensions>();
            appleExtensions.RestoreTransactions(RestroedHandle);
        }
        else if (m_PayType == PayType.Google)
        {
            IGooglePlayStoreExtensions googleExtensions = m_Extensions.GetExtension<IGooglePlayStoreExtensions>();
            googleExtensions.RestoreTransactions(RestroedHandle);
        }
        else if (m_PayType == PayType.UDP)
        {
            IUDPExtensions udpExtensions = m_Extensions.GetExtension<IUDPExtensions>();
            //udpExtensions.(RestroedHandle);
            GameDebug.Log("RestroePurchase fail , udpExtensions not support");
        }
        else
        {
            GameDebug.Log("RestroePurchase fail , no support platform,platorm:" + Application.platform);
        }
    }
    /// <summary>
    /// 恢复支付回调
    /// </summary>
    /// <param name="result"></param>
    void RestroedHandle(bool result)
    {
        m_InRestoreing = false;
        if (result)
        {
            GameDebug.Log("Restroe success================================");
        }
        else
            GameDebug.Log("Restroe fail================================");
    }

    /// <summary>
    /// 漏单处理
    /// </summary>
    void DropOrderProcessing(string goodsID,string productId , string transactionID, string receipt)
    {
        if (!CheckIapParamNull())
        {
            GameDebug.LogError("invalid pay info, DropOrderProcessing CheckIapParamNull");
            HideMaskAndConfirmPurchase();
            ClearLastPayInfo();
            return;
        }

        GameDebug.LogShowy($"DropOrderProcessing,[lastProductID:{UnityIAPController.curGoodsID}],[lastTransactionID:{transactionID}],[lastReceipt:{receipt}]========================================");

        isDropOrderProcessing = true;
        m_CurProduct = m_Ctrl.products.WithID(UnityIAPController.curGoodsID);
        OnPurchaseSuccess(goodsID, productId, transactionID, receipt);
    }
    /// <summary>
    /// 向服务端发验证请求
    /// </summary>
    /// <param name="productID"></param>
    /// <param name="payType"></param>
    /// <param name="transaction"></param>
    /// <param name="receipt"></param>
    void OnPurchaseSuccess(string goodsID, string  productId, string transaction, string receipt)
    {
        GameDebug.LogShowy($"RequestValidatePurchase,[goodsID:{goodsID}],[internalPid:{productId}],[transaction:{transaction}],[receipt：{receipt}]");

        m_InRestoreing = false;
        shouldCheckRestore = false;
        isDropOrderProcessing = false;

        if (m_IapParam == null)
        {
            if (m_PayFail != null)
                m_PayFail(Localization.instance.GetValue("pay_fail_tips"));
            return;
        }
        
        //通知iap 交易结束
        SendEndTranMsg2IAP();

        //更新ValidPayInfo
        UpdateValidPayInfo(goodsID,productId);

        //清除已验证成功的支付记录
        ClearLastPayInfo();

        HideMaskAndConfirmPurchase();
        
        m_PaySuccess?.Invoke(new PaymentData()
        {
            goodsId =  goodsID,
            productPid =  productId,
            payType =  (int)m_PayType,
            transaction =  transaction,
            receipt = receipt
        });
    }

    

    public void OnInitializeFailed(InitializationFailureReason error)
    {
        GameDebug.Log("<color=red>iap OnInitializeFailed=========================================================</color>");
        switch (error)
        {
            case InitializationFailureReason.AppNotKnown:
                GameDebug.LogError("Is your App correctly uploaded on the relevant publisher console?");
                break;
            case InitializationFailureReason.PurchasingUnavailable:
                GameDebug.LogError("Billing disabled!");
                break;
            case InitializationFailureReason.NoProductsAvailable:
                GameDebug.LogError("No products available for purchase!");
                break;
        }
    }

    /// <summary>
    /// 支付失败回调
    /// </summary>
    /// <param name="i"></param>
    /// <param name="p"></param>
    public void OnPurchaseFailed(Product i, PurchaseFailureReason failureReason)
    {
        GameDebug.Log($"OnPurchaseFailed ========================= failureReason：{failureReason}   {i.availableToPurchase}");

        //关闭屏蔽点击遮罩
        HideMaskAndConfirmPurchase();

        //若恢复购买中，则不弹提示
        if (!m_InRestoreing)
        {
            if (m_PayFail != null)
                m_PayFail(Localization.instance.GetValue("pay_fail_tips"));
        }

        m_InRestoreing = false;
        shouldCheckRestore = false;

        //SendRequset_Payment_Fail(UnityPurchaseFailureReason2PayFailureReason(failureReason));

        ClearLastPayInfo();
    }

    public static PayFailureReason UnityPurchaseFailureReason2PayFailureReason(PurchaseFailureReason failureReason)
    {
        if (failureReason == PurchaseFailureReason.PurchasingUnavailable)
            return PayFailureReason.PurchasingUnavailable;
        if (failureReason == PurchaseFailureReason.ExistingPurchasePending)
            return PayFailureReason.ExistingPurchasePending;
        if (failureReason == PurchaseFailureReason.ProductUnavailable)
            return PayFailureReason.ProductUnavailable;
        if (failureReason == PurchaseFailureReason.SignatureInvalid)
            return PayFailureReason.SignatureInvalid;
        if (failureReason == PurchaseFailureReason.UserCancelled)
            return PayFailureReason.UserCancelled;
        if (failureReason == PurchaseFailureReason.PaymentDeclined)
            return PayFailureReason.UserCancelled;
        if (failureReason == PurchaseFailureReason.DuplicateTransaction)
            return PayFailureReason.UserCancelled;

        return PayFailureReason.Unknown;
    }


    public static PayType GetPayType()
    {
        StandardPurchasingModule module = StandardPurchasingModule.Instance();
        
        GameDebug.LogShowy($"module.appStore:{module.appStore}");
#if TEST
        return PayType.EDITOR;
#endif
       
 #if UNITY_IOS
        return PayType.IOS;
#else
        if (module.appStore == AppStore.GooglePlay)
        {
            return  PayType.Google;
        }
        else  if (module.appStore == AppStore.UDP)
        {
            return PayType.UDP;
        }
        else
        {
            GameDebug.LogError($"其他PayType no support:{module.appStore}");
            return PayType.UDP;
        }
#endif
        return (int)PayType.None;
    }

    /// <summary>
    /// 通知unityiap 结束交易
    /// </summary>
    void SendEndTranMsg2IAP()
    {
        if (m_CurProduct == null || !hasInited)
        {
            return;
        }

        if (string.IsNullOrEmpty(m_CurProduct.transactionID))
        {
            GameDebug.LogError("SendEndTranMsg2IAP,m_CurProduct.transactionID is null");
            return;
        }

        m_Ctrl.ConfirmPendingPurchase(m_CurProduct);
        GameDebug.Log($"通知unityiap 结束交易=productID:{m_CurProduct.definition.id}==transactionID:{m_CurProduct.transactionID}=============================================");

        m_CurProduct = null;
    }

    /// <summary>
    /// 弹窗提示
    /// </summary>
    /// <param name="message"></param>
    void ShowNotice(string message)
    {
        HideMaskAndConfirmPurchase();
        GameDebug.LogShowy(message);
        GameCtrl.Instance.ShowNoticePanel(message);
    }

    /// <summary>
    /// 隐藏遮罩，发送结束交易的通知到iap
    /// </summary>
    void HideMaskAndConfirmPurchase()
    {
        //HideMask();
        SendEndTranMsg2IAP();
    }

    /// <summary>
    /// 清除已验证成功的支付记录
    /// </summary>
    void ClearLastPayInfo()
    {
        GameDebug.LogShowy("ClearLastPayInfo");
        ClearLastRecord();
        shouldCheckRestore = false;
        m_IapParam = null;
        m_CurProduct = null;
    }

    void ClearLastRecord()
    {
        GameDebug.LogShowy("ClearLastRecord");
        curGoodsID = "";
        curReceipt = "";
        curTransactionID = "";
        curProductId = "";
    }

    /// <summary>
    /// 用于确保IapParam参数不为空
    /// </summary>
    /// <returns></returns>
    bool CheckIapParamNull()
    {
        try
        {
            //正常的支付逻辑m_IapParam必定不为空,漏单处理时m_IapParam为空
            if (m_IapParam == null)
            {
                if (string.IsNullOrEmpty(curGoodsID))
                {
                    GameDebug.Log("CheckIapParamNull lastProductID is null");
                    return false;
                }

                if (string.IsNullOrEmpty(curProductId))
                {
                    GameDebug.Log("CheckIapParamNull lastInternalPid is null");
                    return false;
                }

                GameDebug.LogShowy("CheckIapParamNull new m_IapParam");
                m_IapParam = new IAPParam(curGoodsID, curProductId);
            }

            return true;
        }
        catch (Exception e)
        {
            GameDebug.LogError("CheckIapParamNull error:" + e);
            ShowNotice("CheckIapParamNull error");
            return false;
        }
    }

    void LogLastPayInfo()
    {
        GameDebug.Log("#lastProductID:" + curGoodsID);
        GameDebug.Log("#lastReceipt:" + curReceipt);
        GameDebug.Log("#lastTransactionID:" + curTransactionID);
        GameDebug.Log("#lastInternalPid:" + curProductId);
    }

    /// <summary>
    /// 获取本地价格
    /// </summary>
    /// <param name="productIp"></param>
    /// <returns></returns>
    public string GetLocalPriceString(string productIp)
    {
        if (hasInited && m_Products != null)
        {
            return m_Products.GetLocalPriceString(productIp);
        }
        else
        {
            return "";
        }
    }


#if UNITY_EDITOR
    [UnityEditor.MenuItem("Tools/IAP/清除上一次的购买记录")]
    static void EditorClearRecord()
    {
        curGoodsID = "";
        curReceipt = "";
        curTransactionID = "";
        curProductId = "";
        PlayerPrefs.SetString(KEY_NotValidPayInfo, "");
        shouldCheckRestore = false;
        GameDebug.Log("成功清除上一次的购买记录");
    }

    static string Key_Editor_PayType = "Key_Editor_PayType";

    [UnityEditor.MenuItem("Tools/IAP/编辑器下设为ios支付")]
    static void SetIosPay()
    {
        GameDebug.Log("编辑器下设为ios支付");
        PlayerPrefs.SetString(Key_Editor_PayType, PayType.IOS.ToString());
    }

    [UnityEditor.MenuItem("Tools/IAP/编辑器下设为google支付")]
    static void SetGooglePay()
    {
        GameDebug.Log("编辑器下设为google支付");
        PlayerPrefs.SetString(Key_Editor_PayType, PayType.Google.ToString());
    }
    [UnityEditor.MenuItem("Tools/IAP/编辑器下设为UDP支付")]
    static void SetUDPPay()
    {
        GameDebug.Log("编辑器下设为UDP支付");
        PlayerPrefs.SetString(Key_Editor_PayType, PayType.UDP.ToString());
    }
    public static PayType editorPayType
    {
        get
        {
            string typeStr = PlayerPrefs.GetString(Key_Editor_PayType, PayType.IOS.ToString());
            if (typeStr.Equals(PayType.IOS.ToString()))
            {
                return PayType.IOS;
            }
            else if (typeStr.Equals(PayType.Google.ToString()))
            {
                return PayType.Google;
            }
            else if (typeStr.Equals(PayType.UDP.ToString()))
            {
                return PayType.UDP;
            }
            GameDebug.LogError("editor payType, no support type,typeStr:" + typeStr);
            return PayType.IOS;
        }
    }

#endif

}
#endif